﻿// =====================================================================
//  This file is part of the Microsoft Dynamics CRM SDK code samples.
//
//  Copyright (C) Microsoft Corporation.  All rights reserved.
//
//  This source code is intended only as a supplement to Microsoft
//  Development Tools and/or on-line documentation.  See these other
//  materials for detailed information regarding Microsoft code samples.
//
//  THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
//  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
//  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
//  PARTICULAR PURPOSE.
// =====================================================================

//<snippetCrmServiceHelper>
using System;
using System.Collections.Generic;
using System.ServiceModel.Description;

// These namespaces are found in the Microsoft.Xrm.Sdk.dll assembly
// located in the SDK\bin folder of the SDK download.
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Sdk.Discovery;
using System.Text;
using Microsoft.Xrm.Sdk;
using McTools.Xrm.Connection;


	public enum AuthenticationType { AD, Passport, SPLA };

	/// <summary>
	/// Provides server connection information.
	/// </summary>
	public class ServerConnection
	{
		#region Inner classes
		/// <summary>
		/// Stores CRM server configuration information.
		/// </summary>
		public class Configuration
		{
			public String ServerAddress;
			public String OrganizationName;
			public Uri DiscoveryUri;
			public Uri OrganizationUri;
			public Uri HomeRealmUri = null;
			public ClientCredentials DeviceCredentials = null;
			public ClientCredentials Credentials = null;
			public AuthenticationType EndpointType;
		}

		#endregion Inner classes

		#region Public properties

		public List<Configuration> configurations = null;

        public Configuration config = new Configuration();

        #endregion Public properties

        #region Public methods
        /// <summary>
		/// Obtains the server connection information including the target organization's
		/// Uri and user login credentials from the user.
		/// </summary>
		public virtual Configuration GetServerConfiguration(ConnectionDetail detail, Guid applicationId)
		{
            try
            {
                // Get the server address. If no value is entered, default to Microsoft Dynamics
                // CRM Online in the North American data center.
                config.ServerAddress = detail.ServerName + (detail.ServerPort.Length > 0 ? ":" + detail.ServerPort : "");

                if (config.ServerAddress.EndsWith("dynamics.com") && detail.UseOsdp )
                {
                    config.DiscoveryUri = new Uri(String.Format("{0}://disco.{1}/XRMServices/2011/Discovery.svc",
                        detail.UseSsl ? "https" : "http",
                        config.ServerAddress));

                    // Set or get the device credentials. Required for Windows Live ID authentication. 
                    config.DeviceCredentials = GetDeviceCredentials(applicationId);
                }
                else if (config.ServerAddress.EndsWith("dynamics.com") && detail.UseOnline)
                {
                    config.DiscoveryUri = new Uri(String.Format("{0}://dev.{1}/XRMServices/2011/Discovery.svc",
                       detail.UseSsl ? "https" : "http",
                       config.ServerAddress));

                    // Set or get the device credentials. Required for Windows Live ID authentication. 
                    config.DeviceCredentials = GetDeviceCredentials(applicationId);
                }
                else
                {
                    config.DiscoveryUri = new Uri(String.Format("{0}://{1}/XRMServices/2011/Discovery.svc",
                           detail.UseSsl ? "https" : "http",
                           config.ServerAddress));
                }

                if (detail.UseIfd)
                {
                    detail.AuthType = AuthenticationProviderType.Federation;
                    //config.EndpointType = AuthenticationType.SPLA;
                }
                else if (detail.UseOsdp)
                {
                    detail.AuthType = AuthenticationProviderType.OnlineFederation;
                    //config.EndpointType = AuthenticationType.Passport;
                }
                else if (detail.UseOnline)
                {
                    detail.AuthType = AuthenticationProviderType.LiveId;
                    //config.EndpointType = AuthenticationType.Passport;
                }
                else
                {
                    detail.AuthType = AuthenticationProviderType.ActiveDirectory;
                    //config.EndpointType = AuthenticationType.AD;
                }


                // Get the user's logon credentials.
                config.Credentials = GetUserLogonCredentials(detail.IsCustomAuth, detail.AuthType, detail.UserName, detail.UserPassword, detail.UserDomain);
                config.HomeRealmUri = detail.HomeRealmUrl != null ? new Uri(detail.HomeRealmUrl) : null;

                return config;
            }
            catch (UriFormatException)
            {
                throw new Exception("The server name specified is not valid for an Uri!");
            }
		}

		/// <summary>
		/// Discovers the organizations that the calling user belongs to.
		/// </summary>
		/// <param name="service">A Discovery service proxy instance.</param>
		/// <returns>Array containing detailed information on each organization that 
		/// the user belongs to.</returns>
		public OrganizationDetailCollection DiscoverOrganizations(IDiscoveryService service)
		{
			RetrieveOrganizationsRequest orgRequest = new RetrieveOrganizationsRequest();
			RetrieveOrganizationsResponse orgResponse =
				(RetrieveOrganizationsResponse)service.Execute(orgRequest);

			return orgResponse.Details;
		}

		/// <summary>
		/// Finds a specific organization detail in the array of organization details
		/// returned from the Discovery service.
		/// </summary>
		/// <param name=orgFriendlyName">The friendly name of the organization to find.</param>
		/// <param name="orgDetails">Array of organization detail object returned from the discovery service.</param>
		/// <returns>Organization details or null if the organization was not found.</returns>
		/// <seealso cref="DiscoveryOrganizations"/>
		public OrganizationDetail FindOrganization(string orgFriendlyName, OrganizationDetail[] orgDetails)
		{
			OrganizationDetail orgDetail = null;

			foreach (OrganizationDetail detail in orgDetails)
			{
				if (String.Compare(detail.FriendlyName, orgFriendlyName) == 0)
				{
					orgDetail = detail;
					break;
				}
			}

			return orgDetail;
		}

		/// <summary>
		/// Reads a server configuration file.
		/// </summary>
		/// <param name="pathname">The file system path to the server configuration file.</param>
		/// <remarks>Server configurations are appended to the public configurations list.</remarks>
		public void ReadConfigurations(String pathname)
		{
			//if (configurations == null)
			//    configurations = new List<Configuration>();

			throw new System.NotImplementedException();
		}

		/// <summary>
		/// Writes all server configurations to a file.
		/// </summary>
		/// <remarks>If the file exists, it is overwritten.</remarks>
		/// <param name="pathname">The file name and system path of the output configuration file.</param>
		public void SaveConfigurations(String pathname)
		{
			if (configurations == null)
				throw new Exception("No server connection configurations were found.");

			//TODO: Delete file if it exists.
			// Delete file here.

			foreach (Configuration config in configurations)
				SaveConfiguration(pathname, config, true);
		}

		/// <summary>
		/// Writes a server configuration to a file.
		/// </summary>
		/// <param name="pathname">The file name and system path of the output configuration file.</param>
		/// <param name="config">A server connection configuration.</param>
		/// <param name="append">If true, the configuration is appended to the file, otherwise a new file
		/// is created.</param>
		public void SaveConfiguration(String pathname, Configuration config, bool append)
		{
			throw new System.NotImplementedException();
		}

		/// <summary>
		/// Obtains the authentication type of the CRM server.
		/// </summary>
		/// <param name="uri">Uri of the CRM Discovery service.</param>
		/// <returns>Authentication type.</returns>
		public AuthenticationProviderType GetServerType(Uri uri)
		{
			return ServiceConfigurationFactory.CreateConfiguration<IDiscoveryService>(uri).AuthenticationType;
		}
		#endregion Public methods

		#region Protected methods

		/// <summary>
		/// Obtains the name and port of the server running the Microsoft Dynamics CRM
		/// Discovery service.
		/// </summary>
		/// <returns>The server's network name and optional TCP/IP port.</returns>
		protected virtual String GetServerAddress()
		{
			Console.Write("Enter a CRM server name and port [crm.dynamics.com]: ");
			String server = Console.ReadLine();


			return server;
		}

		/// <summary>
		/// Obtains the Web address (Uri) of the target organization.
		/// </summary>
		/// <param name="discoveryServiceUri">The Uri of the CRM Discovery service.</param>
		/// <returns>Uri of the organization service or an empty string.</returns>
		protected virtual Uri GetOrganizationAddress(Uri discoveryServiceUri)
		{
			using (DiscoveryServiceProxy serviceProxy = new DiscoveryServiceProxy(discoveryServiceUri, null, config.Credentials, config.DeviceCredentials))
			{
				// Obtain organization information from the Discovery service. 
				if (serviceProxy != null)
				{
					// Obtain information about the organizations that the system user belongs to.
					OrganizationDetailCollection orgs = DiscoverOrganizations(serviceProxy);

					if (orgs.Count > 0)
					{
						Console.WriteLine("\nList of organizations that you belong to:");
						for (int n = 0; n < orgs.Count; n++)
							Console.Write("\n({0}) {1}\t", n + 1, orgs[n].FriendlyName);

						Console.Write("\n\nSpecify an organization number (1-{0}) [1]: ", orgs.Count);
						String input = Console.ReadLine();
						if (input == String.Empty) input = "1";
						int orgNumber = Int32.Parse(input);

						if (orgNumber > 0 && orgNumber <= orgs.Count)
							// Return the organization Uri.
							return new System.Uri(orgs[orgNumber - 1].Endpoints[EndpointType.OrganizationService]);
						else
							throw new Exception("The specified organization does not exist.");
					}
					else
					{
						Console.WriteLine("\nYou do not belong to any organizations on the specified server.");
						return new System.Uri(String.Empty);
					}
				}
				else
					throw new Exception("An invalid server name was specified.");
			}
		}

		/// <summary>
        /// Obtient les informations de connexion
        /// </summary>
        /// <param name="isCustomAuthentication">Authentification personnalisée</param>
        /// <param name="authenticationType">Type d'autnhentification</param>
        /// <param name="userName">Nom d'utilisateur</param>
        /// <param name="password">Mot de passe de l'utilisateur</param>
        /// <param name="domain">Domaine de l'utilisateur</param>
        /// <returns>Informations de droits d'accès</returns>
        protected virtual ClientCredentials GetUserLogonCredentials(bool isCustomAuthentication, AuthenticationProviderType authenticationType, string userName, string password, string domain)
        {
            ClientCredentials credentials = new ClientCredentials(); ;

            if (authenticationType == AuthenticationProviderType.ActiveDirectory)
            {
                if (isCustomAuthentication)
                {
                    credentials.Windows.ClientCredential = new System.Net.NetworkCredential(userName, password, domain);
                }
                else
                {
                    credentials.Windows.ClientCredential = System.Net.CredentialCache.DefaultNetworkCredentials;
                }
            }
            else if (authenticationType == AuthenticationProviderType.LiveId || authenticationType == AuthenticationProviderType.Federation || authenticationType == AuthenticationProviderType.OnlineFederation)
            {
                credentials.UserName.UserName = userName;
                credentials.UserName.Password = password;
            }
            //else if (authenticationType == AuthenticationProviderType.Federation)
            //{
            //    // TODO Ajouter l'authentification IFD
            //    throw new Exception("L'authentification IFD n'est pas encore implémentée");
            //}
            else
            {
                return null;
            }

            return credentials;
        }

		protected virtual ClientCredentials GetDeviceCredentials(Guid applicationId)
		{
            return DeviceIdManager.LoadOrRegisterDevice(applicationId);

		}
		#endregion Private methods
	}

	#region Internal Classes

	//<snippetCrmServiceHelper1>
	/// <summary>
	/// The SolutionComponentType defines the type of solution component.
	/// </summary>
	public static class SolutionComponentType
	{
		public const int Attachment = 35;
		public const int Attribute = 2;
		public const int AttributeLookupValue = 5;
		public const int AttributeMap = 47;
		public const int AttributePicklistValue = 4;
		public const int ConnectionRole = 63;
		public const int ContractTemplate = 37;
		public const int DisplayString = 22;
		public const int DisplayStringMap = 23;
		public const int DuplicateRule = 44;
		public const int DuplicateRuleCondition = 45;
		public const int EmailTemplate = 36;
		public const int Entity = 1;
		public const int EntityMap = 46;
		public const int EntityRelationship = 10;
		public const int EntityRelationshipRelationships = 12;
		public const int EntityRelationshipRole = 11;
		public const int FieldPermission = 71;
		public const int FieldSecurityProfile = 70;
		public const int Form = 24;
		public const int KBArticleTemplate = 38;
		public const int LocalizedLabel = 7;
		public const int MailMergeTemplate = 39;
		public const int ManagedProperty = 13;
		public const int OptionSet = 9;
		public const int Organization = 25;
		public const int PluginAssembly = 91;
		public const int PluginType = 90;
		public const int Relationship = 3;
		public const int RelationshipExtraCondition = 8;
		public const int Report = 31;
		public const int ReportCategory = 33;
		public const int ReportEntity = 32;
		public const int ReportVisibility = 34;
		public const int RibbonCommand = 48;
		public const int RibbonContextGroup = 49;
		public const int RibbonCustomization = 50;
		public const int RibbonDiff = 55;
		public const int RibbonRule = 52;
		public const int RibbonTabToCommandMap = 53;
		public const int Role = 20;
		public const int RolePrivilege = 21;
		public const int SavedQuery = 26;
		public const int SavedQueryVisualization = 59;
		public const int SDKMessageProcessingStep = 92;
		public const int SDKMessageProcessingStepImage = 93;
		public const int SDKMessageProcessingStepSecureConfig = 94;
		public const int ServiceEndpoint = 95;
		public const int SiteMap = 62;
		public const int SystemForm = 60;
		public const int ViewAttribute = 6;
		public const int WebResource = 61;
		public const int Workflow = 29;
	}
	//</snippetCrmServiceHelper1>
	#endregion

//</snippetCrmServiceHelper>
